namespace SubSonic.CodeGenerator
{
    using SubSonic;
    using System;
    using System.Collections.Specialized;
    using System.IO;
    using System.Reflection;
    using System.Text;
    using System.Text.RegularExpressions;

    [Serializable]
    public class TurboTemplate
    {
        private bool addUsingBlock = true;
        private static ICodeLanguage compileLanguage;
        private readonly string customUsingBlock = string.Empty;
        private string entryPoint = "Render";
        private string finalCode;
        private const string FOOTER = "\r\n\r\n                    StreamReader sr = new StreamReader(mStream); \r\n\t\t\t        writer.Flush();\r\n\t\t\t        mStream.Position = 0;\r\n\t\t\t        return sr.ReadToEnd();\r\n\t\t        }\r\n\t        }";
        private string generatedRenderType = "Parser";
        private const string HEADER = "using System;\r\n            using System.Text.RegularExpressions;\r\n            using System.Collections;\r\n            using System.IO;\r\n            using System.Text;\r\n            using SubSonic;\r\n            using SubSonic.CodeGenerator;\r\n            using System.Data;\r\n            using System.Configuration;\r\n            using SubSonic.Utilities;\r\n            \r\n\t        public class Parser#TEMPLATENUMBER#\r\n\t        {\r\n\t\t        public static string Render()\r\n\t\t        {\r\n\t\t\t        MemoryStream mStream = new MemoryStream();\r\n\t\t\t        StreamWriter writer = new StreamWriter(mStream, System.Text.Encoding.UTF8);\r\n                    writer.AutoFlush = false;\r\n\r\n                ";
        private string outputPath;
        private static StringCollection references;
        private readonly ICodeLanguage renderLanguage = new CSharpCodeLanguage();
        private string templateName = string.Empty;
        private string templateText;

        public TurboTemplate(string templateInputText, ICodeLanguage language, DataProvider provider)
        {
            this.renderLanguage = language;
            this.templateText = CleanTemplate(templateInputText + "<%%>", ref this.renderLanguage);
            if (provider.AdditionalNamespaces.Length > 0)
            {
                this.customUsingBlock = this.renderLanguage.GetUsingStatements(provider.AdditionalNamespaces);
            }
        }

        private static string CleanCalls(Match m)
        {
            return Regex.Replace(Regex.Replace(m.ToString(), "<%=", "\t\t\twriter.Write("), "%>", ");");
        }

        private static string CleanCodeTags(Match m)
        {
            string str = m.ToString();
            str = str.Substring(2, str.Length - 4);
            return ("\t\t\t" + str);
        }

        private static string CleanTemplate(string templateInputText, ref ICodeLanguage language)
        {
            templateInputText = Regex.Replace(templateInputText, @"(?i)<%@\s*Property.*?%>", string.Empty);
            templateInputText = Regex.Replace(templateInputText, @"(?i)<%@\s*Assembly.*?%>", string.Empty);
            templateInputText = Regex.Replace(templateInputText, @"(?i)<%@\s*Import.*?%>", string.Empty);
            templateInputText = Regex.Replace(templateInputText, @"(?i)<%@\s*CodeTemplate.*?%>", string.Empty);
            templateInputText = ParseTemplate(templateInputText);
            templateInputText = Regex.Replace(templateInputText, "<%=.*?%>", new MatchEvaluator(TurboTemplate.CleanCalls), RegexOptions.Singleline);
            templateInputText = Regex.Replace(templateInputText, "<%%>", string.Empty, RegexOptions.Singleline);
            templateInputText = Regex.Replace(templateInputText, "<%[^=|@].*?%>", new MatchEvaluator(TurboTemplate.CleanCodeTags), RegexOptions.Singleline);
            templateInputText = Regex.Replace(templateInputText, @"(?i)<%@\s*Page.*?%>", string.Empty);
            StringBuilder builder = new StringBuilder("using System;\r\n            using System.Text.RegularExpressions;\r\n            using System.Collections;\r\n            using System.IO;\r\n            using System.Text;\r\n            using SubSonic;\r\n            using SubSonic.CodeGenerator;\r\n            using System.Data;\r\n            using System.Configuration;\r\n            using SubSonic.Utilities;\r\n            \r\n\t        public class Parser#TEMPLATENUMBER#\r\n\t        {\r\n\t\t        public static string Render()\r\n\t\t        {\r\n\t\t\t        MemoryStream mStream = new MemoryStream();\r\n\t\t\t        StreamWriter writer = new StreamWriter(mStream, System.Text.Encoding.UTF8);\r\n                    writer.AutoFlush = false;\r\n\r\n                ");
            builder.Append(templateInputText);
            builder.Append("\r\n\r\n                    StreamReader sr = new StreamReader(mStream); \r\n\t\t\t        writer.Flush();\r\n\t\t\t        mStream.Position = 0;\r\n\t\t\t        return sr.ReadToEnd();\r\n\t\t        }\r\n\t        }");
            return builder.ToString().Trim();
        }

        public static string LoadTextFromManifest(string templateFileName)
        {
            string str = null;
            Stream manifestResourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("SubSonic.CodeGeneration.Templates." + templateFileName);
            if (manifestResourceStream != null)
            {
                StreamReader reader = new StreamReader(manifestResourceStream);
                str = reader.ReadToEnd();
                reader.Close();
            }
            return str;
        }

        private static string ParseTemplate(string templateInputText)
        {
            if (string.IsNullOrEmpty(templateInputText))
            {
                return string.Empty;
            }
            MemoryStream stream = new MemoryStream();
            StreamWriter writer = new StreamWriter(stream, Encoding.UTF8);
            int startIndex = 0;
            int index = templateInputText.IndexOf("<%", 0);
            if (index != -1)
            {
                while (index > -1)
                {
                    if (index > -1)
                    {
                        writer.Write("\t\t\twriter.Write(@\"" + templateInputText.Substring(startIndex, index - startIndex).Replace("\"", "\"\"") + "\" );");
                    }
                    int num3 = templateInputText.IndexOf("%>", index);
                    if (num3 < 0)
                    {
                        break;
                    }
                    writer.Write(templateInputText.Substring(index, (num3 - index) + 2));
                    startIndex = num3 + 2;
                    index = templateInputText.IndexOf("<%", startIndex);
                    if (index < 0)
                    {
                        writer.Write("\t\t\twriter.Write(@\"" + templateInputText.Substring(startIndex, templateInputText.Length - startIndex).Replace("\"", "\"\"") + "\" );");
                    }
                }
            }
            else
            {
                return templateInputText;
            }
            writer.Flush();
            stream.Position = 0L;
            StreamReader reader = new StreamReader(stream);
            string str = reader.ReadToEnd();
            reader.Close();
            stream.Close();
            writer.Close();
            return str;
        }

        public string Render()
        {
            if (string.IsNullOrEmpty(this.TemplateText))
            {
                return string.Empty;
            }
            TurboCompiler compiler = new TurboCompiler();
            compiler.AddTemplate(this);
            compiler.Run();
            return compiler.Templates[0].FinalCode;
        }

        public bool AddUsingBlock
        {
            get
            {
                return this.addUsingBlock;
            }
            set
            {
                this.addUsingBlock = value;
            }
        }

        public ICodeLanguage CompileLanguage
        {
            get
            {
                if (compileLanguage == null)
                {
                    compileLanguage = new CSharpCodeLanguage();
                }
                return compileLanguage;
            }
        }

        public string CustomUsingBlock
        {
            get
            {
                return this.customUsingBlock;
            }
        }

        public string EntryPoint
        {
            get
            {
                return this.entryPoint;
            }
            set
            {
                this.entryPoint = value;
            }
        }

        public string FinalCode
        {
            get
            {
                return this.finalCode;
            }
            set
            {
                this.finalCode = value;
            }
        }

        public string GeneratedRenderType
        {
            get
            {
                return this.generatedRenderType;
            }
            set
            {
                this.generatedRenderType = value;
            }
        }

        public string OutputPath
        {
            get
            {
                return this.outputPath;
            }
            set
            {
                this.outputPath = value;
            }
        }

        public StringCollection References
        {
            get
            {
                if (references == null)
                {
                    references = new StringCollection();
                    references.Add("System.dll");
                    references.Add("System.Data.dll");
                    references.Add("System.Drawing.dll");
                    references.Add("System.Xml.dll");
                    references.Add("System.Windows.Forms.dll");
                    references.Add("System.Configuration.dll");
                    references.Add(typeof(TurboTemplate).Assembly.Location);
                }
                return references;
            }
        }

        public ICodeLanguage RenderLanguage
        {
            get
            {
                return this.renderLanguage;
            }
        }

        public string TemplateName
        {
            get
            {
                return this.templateName;
            }
            set
            {
                this.templateName = value;
            }
        }

        public string TemplateText
        {
            get
            {
                return this.templateText;
            }
            set
            {
                this.templateText = value;
            }
        }
    }
}

